/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/

import { BaseCommand, FeatureManager, pickedLineData } from '@amcax/base';
import { generateProductPickObj } from '@app-base/common/components/pick-input/pick-product';
import { PickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { useCommand } from '@app-cad/common/hooks/useCommand';
import { useTools } from '@app-cad/common/hooks/useTools';
import { getIdOfPickedObj } from '@app-cad/common/utils/render';
import { ctx2 } from '@app-cad/module';
import { FeaturedCmdDialogParams } from '@app-cad/types';
import { useAsyncEffect } from 'ahooks';
import i18n from 'i18next';
import { useMemo, useRef, useState } from 'react';
import { get1stLevelPartFromId } from '../../utils';
import { useDollyCamera } from '../common/hooks/useDollyCamera';
import {
  clearArrayCommandPreview,
  executeArrayCommand,
  onArrayCommandExit,
} from '../common/utils/ArrayUtils';
import { extraUiSchema, schema } from './form-definition';
import { FormData } from './types';

const initData: FormData = {
  base: null,
  direction: null,
  distance: 10,
  count: 2,
  reverse: false,
  useDir2: false,
  direction2: null,
  distance2: 10,
  count2: 2,
  reverse2: false,
  skipInstances: false,
};

function LinearArray({
  title,
  onClose,
  placement,
  props,
}: FeaturedCmdDialogParams) {
  useDollyCamera();

  const [formData, setFormData] = useState<FormData>(initData);
  const { pickerAssembly } = useTools();

  const skippedIds = useRef<number[]>([]);

  useAsyncEffect(async () => {
    if (props == null) {
      setFormData(initData);
      return;
    }

    const {
      base,
      direction,
      distance,
      count,
      reverse = false,
      useDir2 = false,
      direction2,
      distance2 = 10,
      count2 = 2,
      reverse2 = false,
      skipids = [],
    } = props.params;

    skippedIds.current = skipids;

    const baseObj = generateProductPickObj(get1stLevelPartFromId(base));
    const dirObj =
      direction &&
      (pickerAssembly.generatePickObjByPickID(direction) as pickedLineData);
    const dir2Obj =
      direction2 &&
      (pickerAssembly.generatePickObjByPickID(direction2) as pickedLineData);

    await initEditDependency([base, direction, direction2]);

    setFormData({
      base: baseObj,
      direction: dirObj,
      distance,
      count,
      reverse,
      useDir2,
      direction2: dir2Obj,
      distance2,
      count2,
      reverse2,
      skipInstances: skipids.length > 0,
    });
  }, [props]);

  useAsyncEffect(async () => {
    clearArrayCommandPreview();

    if (!isFormDataValid()) {
      ctx2.viewer.requestRender();

      return;
    }
    await execute(true);
  }, [formData]);

  const isFormDataValid = () => {
    const {
      base,
      direction,
      distance,
      count,
      useDir2,
      direction2,
      distance2,
      count2,
    } = formData;

    const dir1Valid =
      base != null && direction != null && distance != null && count != null;

    const dir2Valid = direction2 != null && distance2 != null && count2 != null;

    return useDir2 ? dir1Valid && dir2Valid : dir1Valid;
  };

  const finishValid = useMemo(isFormDataValid, [formData]);

  const execute = async (preview: boolean = false) => {
    const {
      base,
      direction,
      distance,
      count,
      reverse,
      useDir2,
      direction2,
      distance2,
      count2,
      reverse2,
      skipInstances,
    } = formData;
    const baseID = getIdOfPickedObj(base);
    const params = {
      mode: 'linear',
      direction: getIdOfPickedObj(direction),
      distance,
      count,
      reverse: reverse,
      useDir2,
    };
    const dir2Params = {
      useDir2,
      direction2: getIdOfPickedObj(direction2),
      distance2: distance2,
      count2,
      reverse2: reverse2,
    };
    const validParams = useDir2 ? { ...params, ...dir2Params } : params;

    await executeArrayCommand(
      props,
      baseID,
      validParams,
      preview,
      base,
      skipInstances,
      skippedIds.current,
    );
  };

  const checkAndFinish = async () => {
    if (!isFormDataValid()) {
      return;
    }

    await execute();
    onExit();
  };

  const onExit = () => {
    onArrayCommandExit();
    onClose();
  };

  const { initEditDependency } = useCommand('array-linear', {
    onClose: onExit,
    finishDraw: checkAndFinish,
  });

  if (!FeatureManager.isFeatureEnabled('product-array-skip-instances')) {
    delete schema.properties.skipInstances;
  }

  return (
    <PickableCommandForm
      isFormDataValid={finishValid}
      disabled={false}
      onClose={onExit}
      title={title}
      placement={placement}
      schema={schema}
      formData={formData}
      onChange={(v) => {
        setFormData(v);
      }}
      extraUiSchema={extraUiSchema(setFormData, props)}
      submitText='完成'
      onSubmit={checkAndFinish}
    />
  );
}

export const cmdLinearArray: BaseCommand = {
  id: 'cmdLinearArray',
  label: 'command.product-linear-array',
  icon: 'commands/feature/array-linear',
  create: (label, onClose, props) => (
    <LinearArray
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
    />
  ),
};
